package cn.skyquant.quant4j.service.boot.web.controller;

import cn.skyquant.quant4j.api.account.AccountDTO;
import cn.skyquant.quant4j.api.account.AccountService;
import cn.skyquant.quant4j.api.authority.UserDTO;
import cn.skyquant.quant4j.api.dto.ResultDTO;
import cn.skyquant.quant4j.api.enums.BorkerType;
import cn.skyquant.quant4j.sdk.util.bean.BeanTools;
import cn.skyquant.quant4j.service.boot.model.account.Account;
import cn.skyquant.quant4j.service.boot.model.account.AccountDaily;
import cn.skyquant.quant4j.service.boot.model.account.AccountDailyRepository;
import cn.skyquant.quant4j.service.boot.model.account.AccountRepository;
import cn.skyquant.quant4j.service.boot.model.authority.AppContext;
import cn.skyquant.quant4j.service.boot.model.authority.RoleAuthority;
import cn.skyquant.quant4j.service.boot.model.authority.User;
import cn.skyquant.quant4j.service.boot.web.annotation.NoVerify;
import cn.skyquant.quant4j.service.boot.web.vo.AccountDailyVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/account")
public class AccountController {
    @Autowired
    AccountService accountService;
    @Autowired
    AccountRepository accountRepository;
    @Autowired
    AccountDailyRepository accountDailyRepository;

    @Autowired
    AppContext appContext;

    private static ResultDTO error = ResultDTO.error("参数不正确");

    @RequestMapping(value = "",method = RequestMethod.GET)
    @ResponseBody
    @NoVerify
    public ResultDTO<AccountDTO> get(
            @RequestParam(value = "code",required = true)String code,
            @RequestParam(value = "borker_type",required = true)String borker_type) {
        BorkerType borkerType = BorkerType.valueOf(borker_type);
        if(borkerType==null ){
            return error;
        }
        ResultDTO<AccountDTO> result =  accountService.get(code,borkerType);
        return result;
    }

    @RequestMapping(value = "",method = RequestMethod.POST)
    @ResponseBody
    @NoVerify
    public ResultDTO<AccountDTO> create(
            @RequestParam(value = "code",required = true)String code,
            @RequestParam(value = "borker_type",required = true)String borker_type,
            @RequestParam(value = "name",required = false)String name,
            @RequestParam(value = "borker_name",required = true)String borker_name,
            @RequestParam(value = "currency",required = true)String currency,
            @RequestParam(value = "account_type",required = true)String account_type,
            @RequestParam(value = "parent_code",required = false)String parent_code) {
        BorkerType borkerType = BorkerType.valueOf(borker_type);
        if(borkerType==null ){
            return error;
        }
        ResultDTO<AccountDTO> result =  accountService.create( code, borkerType, account_type,name,  borker_name,  currency ,  parent_code);
        return result;
    }

    @RequestMapping(value = "",method = RequestMethod.PUT)
    public ResultDTO<Void> update(
            @RequestParam(value = "code",required = true)String code,
            @RequestParam(value = "borkerType",required = true)String borkerType,
            @RequestParam(value="balance",required = false) double balance,
            @RequestParam(value="equity",required = false) double equity,
            @RequestParam(value="used_margin",required = false) double usedMargin,
            @RequestParam(value="borker_time",required = true) long borkerTime) {
        return accountService.update(code,BorkerType.valueOf(borkerType),balance,equity,usedMargin,borkerTime);
    }


    @RequestMapping(value = "/notice",method = RequestMethod.GET)
    public ResultDTO<Void> balanceNotice(
            @RequestParam(value = "accountId",required = true)Integer accountId){
        return accountService.notice(accountId);
    }

    @RequestMapping(value="/list",method = RequestMethod.GET)
    public List<AccountDTO> list() {
        List<AccountDTO> accountDTOS = new ArrayList<>();
        UserDTO userDTO = appContext.get();
        if(userDTO!=null){
            Iterable<Account> accounts;
            if(userDTO.containRole(RoleAuthority.administrator)){
                accounts = accountRepository.findAll();
            }else {
                User user = new User();
                user.id = userDTO.id;
                accounts = accountRepository.findByUser(user);
            }
            accounts.forEach(x->accountDTOS.add(convertAccountToAccountDTO(x)));
        }
        return accountDTOS;
    }

    @RequestMapping(value="/{id}/his",method = RequestMethod.GET)
    public ResultDTO<List<AccountDailyVO>> his(@PathVariable int id) {
        Optional<Account> optionalAccount = accountRepository.findById(id);
        List<AccountDailyVO> accountDailyList = new ArrayList<>();
        if(optionalAccount.isPresent()){
            Account account = optionalAccount.get();
            List<AccountDaily> dailyList = accountDailyRepository.findByAccount(account);
            accountDailyList.addAll(dailyList.stream().map(x->convert(x)).collect(Collectors.toList()) );
        }

        return ResultDTO.success(accountDailyList);
    }

    @RequestMapping(value="/{id}/updateType",method = RequestMethod.POST)
    public ResultDTO<Void> updateType(@PathVariable int id,
                                               @RequestParam String type) {
        return accountService.updateType(id,type);
    }

    private static final AccountDailyVO convert(AccountDaily accountDaily){
        AccountDailyVO accountDailyVO = new AccountDailyVO();
        accountDailyVO.date = accountDaily.borkerTime;
        accountDailyVO.equity = accountDaily.equity;
        return accountDailyVO;
    }

    private static final AccountDTO convertAccountToAccountDTO(Account account){
        AccountDTO accountDTO = new AccountDTO();
        BeanTools.copyPublicFields(account,accountDTO);
        return accountDTO;
    }
}
